home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / SOUND / SBDSP.ARJ / SBDSP.C < prev    next >
Text File  |  1992-04-17  |  13KB  |  418 lines

  1.  
  2. /*
  3.    SBDSP - a program to allow the use of SoundBlaster audio I/O boards
  4.        for APT satellite image capture/demodulation.
  5.  
  6.        Written by:    Mark S. Sims
  7.             Box 1601 SMU
  8.             Dallas, TX 75275
  9.  
  10.        Compiled with: Microsoft Quick C 2.0 / MSC 6.0
  11.  
  12.        Copyright (C) 1992 by Mark S. Sims.
  13.        This program may be freely copied and distributed as long
  14.        as this message stays intact.  Commercial or for-profit
  15.        distribution,  modification,  or use is strictly prohibited.
  16.  
  17.        Use and modify at your own risk 'til your heart's content
  18.        as long as all modifications remain in the public domain.
  19.  
  20.        A good place to start would be to add automatic image centering
  21.        or a software PLL to remove the dopple bow.    Or perhaps an
  22.        optional noise filter.  Or calculate the demodulator table
  23.        with integer math and can the floating point library.  Or ...
  24.        well you get the point...
  25.  
  26.  
  27.       Version 1.0 - Initial release
  28. */
  29.  
  30. #define VERSION 0x10
  31.  
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <string.h>
  35. #include <fcntl.h>
  36. #include <io.h>
  37. #include <dos.h>
  38. #include <malloc.h>
  39. #include <stdlib.h>
  40. #include <conio.h>
  41. #include <math.h>
  42.  
  43. #pragma pack(1)    /* we need packed structures! */
  44.  
  45. #define ABS(x) ((x<0)? (0-x): x)
  46. #define SIGN(x) ((x<0)? '-': '+')
  47.  
  48. int    dma_odd = 2;         /* add two pixels to ODD DMA input blocks */
  49. int    dma_even = 3;         /* and three pixels to the EVEN blocks */
  50. int    coarse_tune = (-4808/8); /* and remove every 601st pixel from the stream */
  51. long    fine_tune = (0);     /* +40000 would duplicate every 40,000th pixel */
  52.                  /* -12345 would remove every 12,345th pixel, etc */
  53.  
  54. unsigned char in_name[128];     /* input file name */
  55. FILE *finfile;             /* input file handle */
  56. long readpos;             /* input file read position */
  57.  
  58. unsigned char out_name[128];     /* output file name */
  59. FILE *foutfile;          /* output file handle */
  60. long writepos;             /* output file write position */
  61.  
  62. struct HEADER {       /* SoundBlaster .VOC file DMA block header */
  63.    unsigned char id;
  64.    unsigned short block_size;
  65.    unsigned char size_high;
  66.    unsigned short sample_rate;
  67. } header;
  68.  
  69. #define MAX_BLOCK 32768       /* maximum DMA input block size */
  70. #define MAX_DMA_ADJUST 256    /* how much adjustment we will allow */
  71. unsigned blocks;          /* the input block counter */
  72.  
  73. unsigned char in_buf[MAX_BLOCK + MAX_DMA_ADJUST + 2];
  74. unsigned read_cols = (MAX_BLOCK - sizeof(struct HEADER));
  75.  
  76. int calc_average = 1;    /* set flag to calculate the block sample averages */
  77. long average;        /* where we calculate the average */
  78. unsigned char bias;    /* the resulting DC offset of the SoundBlaster samples */
  79.  
  80. #define BUFLEN        (512*8)     /* DOS writes multiples of 512 bytes fastest */
  81. unsigned char out_buf[BUFLEN];     /* output file buffer */
  82. unsigned outptr;         /* output buffer pointer */
  83.  
  84. unsigned char huge *demod;    /* the demodulator table is allocated here */
  85. unsigned long demod_size;     /* it is this many bytes long */
  86.  
  87.  
  88.  
  89. main(argc, argv)
  90. int  argc;
  91. char *argv[];
  92. {
  93. int i;
  94. int key;
  95.  
  96.    key = ' ';
  97.    for(i=1; i<argc; i++) {  /* process the command line file names */
  98.       if((argv[i][0] != '/') && (argv[i][0] != '-')) set_file(argv[i]);
  99.    }
  100.    if(in_name[0] == 0) goto help;   /* no input file was given */
  101.  
  102.    for(i=1; i<argc; i++) {  /* process the command options */
  103.       if((argv[i][0] == '/') || (argv[i][0] == '-')) {
  104.      key = option_switch(argv[i]);
  105.      if(key) {
  106.         help:
  107.         printf("SBDSP - a program to demodulate APT satellite images from\n");
  108.         printf("        SoundBlaster .VOC audio sample files.  Version %X.%X\n", VERSION>>4, VERSION&0x0F);
  109.         printf("\n");
  110.         printf("        Copyright (C) 1992 by Mark S. Sims.\n");
  111.         printf("        This program may be freely copied and distributed as long\n");
  112.         printf("        as this message stays intact.  Commercial or for-profit\n");
  113.         printf("        distribution or use is strictly prohibited.\n");
  114.         printf("\n");
  115.         printf("*** ERROR: Invalid command line option: %c.  Usage is:\n", key);
  116.         printf("      sbdsp infile [outfile] [/E+val] [/O-val] [/C+val] [/F-val]\n");
  117.         printf("            /E - set even DMA block adjustment factor\n");
  118.         printf("                 (default: /E%c%d)\n", ((dma_even<0) ? '-': '+'), ABS(dma_even));
  119.         printf("            /O - set odd DMA block adjustment factor\n");
  120.         printf("                 (default: /O%c%d)\n", ((dma_odd<0) ? '-': '+'), ABS(dma_odd));
  121.         printf("            /C - set coarse (line) timing adjustment factor\n");
  122.         printf("                 (default: /C%c%d)\n", ((coarse_tune<0) ? '-': '+'), ABS(coarse_tune));
  123.         printf("            /F - set fine (image skew) timing adjustment factor\n");
  124.         printf("                 (default: /F%c%ld)\n", ((fine_tune<0) ? '-': '+'), ABS(fine_tune));
  125.         printf("\n");
  126.         printf("            If *outfile* is not given, the demodulated output image\n");
  127.         printf("            is written over the input sample file (VERY SLOWLY)!\n");
  128.         exit(1);
  129.      }
  130.       }
  131.    }
  132.  
  133.    setup_files();
  134.    build_demodulator();
  135.    demodulate_file();
  136.  
  137.    printf("\n\nDONE!!!  Demodulated %d blocks\n", blocks);
  138.    fclose(finfile);
  139.    if(finfile != foutfile) fclose(foutfile);
  140.    exit(0);
  141. }
  142.  
  143.  
  144. set_file(arg)
  145. char arg[];
  146. {
  147.    if(in_name[0]) strcpy(out_name, arg);
  148.    else strcpy(in_name, arg);
  149.  
  150.    return 0;
  151. }
  152.  
  153.  
  154. option_switch(arg)
  155. char arg[];
  156. {
  157. char c;
  158. int s;
  159. int i;
  160.  
  161.    i = 1;
  162.    c = tolower(arg[i]);     /* the option character */
  163.    s = arg[++i];        /* the sign (+ or -) */
  164.    if(s == '=') {
  165.       s = arg[++i];
  166.    }
  167.    if((s != '+') && (s != '-')) s = 0;
  168.  
  169.    if(c == 'e') {
  170.       if(s == 0) return c;
  171.       sscanf(&arg[i], "%d", &dma_even);
  172.       if(ABS(dma_even) > MAX_DMA_ADJUST) return c;
  173.    }
  174.    else if(c == 'o') {
  175.       if(s == 0) return c;
  176.       sscanf(&arg[i], "%d", &dma_odd);
  177.       if(ABS(dma_odd) > MAX_DMA_ADJUST) return c;
  178.    }
  179.    else if(c == 'c') {
  180.       if(s == 0) return c;
  181.       sscanf(&arg[i], "%d", &coarse_tune);
  182.    }
  183.    else if(c == 'f') {
  184.       if(s == 0) return c;
  185.       sscanf(&arg[i], "%ld", &fine_tune);
  186.    }
  187.    else return c;
  188.  
  189.    return 0;
  190. }
  191.  
  192.  
  193. setup_files()
  194. {
  195. unsigned j;
  196. char c;
  197.  
  198.    finfile = fopen(in_name, "r+b");
  199.    if(finfile == 0) {
  200.       printf("*** ERROR: could not open input file for fread(): %s\n", in_name);
  201.       exit(1);
  202.    }
  203.    j = fread(in_buf, 1, 26, finfile);
  204.    if(j != 26) {
  205.       printf("*** ERROR: could not skip header on input file: %s\n", in_name);
  206.       exit(1);
  207.    }
  208.  
  209.    if(out_name[0]) {    /* output file name was given, write a separate file */
  210.       foutfile = fopen(out_name, "wb");
  211.       if(foutfile == 0) {
  212.      printf("*** ERROR: could not open output file for fwrite(): %s\n", out_name);
  213.      exit(1);
  214.       }
  215.    }
  216.    else {   /* no output file name was given,  overwrite the input */
  217.       while(1) {
  218.      printf("WARNING: No output file name was given.  Overwrite input (Y/N)? ");
  219.      c = getch();
  220.      c = tolower(c);
  221.      printf("\n");
  222.  
  223.      if(c == 'n') {
  224.         printf("OK. I'wont...\n");
  225.         exit(1);
  226.      }
  227.      else if(c == 'y') {
  228.         printf("Overwriting the input file.  Interruption is not recommeded...\n");
  229.         break;
  230.      }
  231.      else printf("\n");
  232.       }
  233.  
  234.       foutfile = finfile;
  235.       readpos = ftell(finfile);  /* where we need to start reading the sample data */
  236.    }
  237.  
  238.    return 0;
  239. }
  240.  
  241.  
  242. build_demodulator()
  243. {
  244. long x, y;
  245. double fscale;
  246. unsigned long index;    /* used to access the demodulator table */
  247. unsigned xm;
  248.  
  249.    demod_size = 256L*256L;
  250.    demod = halloc(demod_size, 1);   /* this is a 64Kb array! */
  251.    if(demod == 0) {
  252.       printf("*** ERROR: could not halloc() %ld bytes of memory.\n", demod_size);
  253.       exit(1);
  254.    }
  255.  
  256.    fscale = 255.0 / sqrt(128.0*128.0 + 128.0*128.0);
  257.    printf("Initializing demodulator tables...");
  258.    for(x=0; x<256; x++) {
  259.       for(y=0; y<256; y++) {
  260.      index = ((x-128) * (x-128)) + ((y-128) * (y-128));
  261.      xm = (unsigned) (sqrt((double) index) * fscale);
  262.      if(xm > 255) xm = 255;
  263.  
  264.      index = (x << 8) | y;
  265.      if(index >= demod_size) {
  266.         printf("\n*** ERROR: demoulator table overflow.\n");
  267.         exit(1);
  268.      }
  269.      demod[index] = xm;
  270.       }
  271.    }
  272.  
  273.    printf("\n");
  274.    return 0;
  275. }
  276.  
  277.  
  278. demodulate_file()
  279. {
  280. unsigned i, j;
  281. int coarse_time;    /* coarse skip rate */
  282. long fine_time;     /* fine skip rate */
  283. int dma_add;        /* end-of-DMA block pixel compensator */
  284. unsigned short index;
  285.  
  286.    printf("\n");
  287.    if(finfile == foutfile) printf("DON'T press ESC to interrupt...\n");
  288.    else printf("Press ESC to interrupt...\n");
  289.    printf("\n");
  290.  
  291.    printf("Demodulating %d byte blocks...\n", read_cols);
  292.    printf(
  293.       "   /O%c%d  /E%c%d  /C%c%d  /F%c%ld\n",
  294.       SIGN(dma_odd),     ABS(dma_odd),
  295.       SIGN(dma_even),     ABS(dma_even),
  296.       SIGN(coarse_tune), ABS(coarse_tune),
  297.       SIGN(fine_tune),     ABS(fine_tune)
  298.    );
  299.  
  300.    blocks = 0;
  301.    outptr = 0;
  302.    coarse_time = 0;
  303.    fine_time = 0;
  304.  
  305.    while(1) {
  306.       if(kbhit()) {   /* the user pressed a key */
  307.      if(getch() == 0x1B) {     /* was it ESC? */
  308.         printf("\n*** INTERRUPTED ***\n");
  309.         break;
  310.      }
  311.      else printf("\007");  /* beep at the fumble fingered klutz */
  312.       }
  313.  
  314.       if(finfile == foutfile) fseek(finfile, readpos, 0);
  315.       j = fread(&header, 1, sizeof(struct HEADER), finfile);  /* block header */
  316.       if(j != sizeof(struct HEADER)) {
  317.      break;
  318.       }
  319.       if(header.id != 0x01) {
  320.      printf("Block header ID %02X is not supported.\n", header.id);
  321.      break;
  322.       }
  323.       else if(header.size_high || (header.block_size > MAX_BLOCK)) {
  324.      printf("Input file block size too big.\n");
  325.      break;
  326.       }
  327.  
  328.       /* the first word in the block (which we actually read in as part */
  329.       /* of the block header) seems to be the sample clock rate code. */
  330.       /* We need to remove it from the block size value... */
  331.       read_cols = header.block_size - 2;
  332.  
  333.       j = fread(in_buf, 1, read_cols, finfile);  /* get data buffer values */
  334.       if(j != read_cols) break;    /* its close to the end-of-file */
  335.       readpos = ftell(finfile);
  336.  
  337.       /* duplicate the last few samples in the block to compensate for those */
  338.       /* lost due to the time VREC spends setting up between DMA blocks */
  339.       if(blocks & 0x01) dma_add = dma_odd; /* ODD blocks need this many */
  340.       else dma_add = dma_even;          /* and EVEN blocks need this many */
  341.  
  342.       if(dma_add > 0) {   /* we are adding pixels to this DMA block */
  343.      for(i=0; i<dma_add; i++) {  /* duplicate the last few pixels */
  344.         in_buf[read_cols+i] = in_buf[read_cols-dma_add+i];
  345.      }
  346.       }
  347.       read_cols += dma_add;  /* adjust the resulting pixel count */
  348.  
  349.       /* calculate the average sample value in the block */
  350.       if(calc_average) {
  351.      /* calc_average = 0; */  /* uncomment if your board's sample bias does not drift */
  352.      average = 0;
  353.      for(i=0; i<read_cols; i++) average += in_buf[i];
  354.      average += (read_cols / 2);   /* round it */
  355.      average /= read_cols;
  356.      bias = (average - 128L);   /* the samples have a net bias */
  357.       }
  358.  
  359.       /* demodulate the block of samples to convert the input APT sine */
  360.       /* wave sample into their corresponding pixel values */
  361.       for(i=0; i<read_cols-1; i++) {
  362.      if((coarse_tune < 0) && (--coarse_time <= coarse_tune)) {
  363.         coarse_time = 0;   /* we are removing excess samples from the line */
  364.      }
  365.      else if((fine_tune < 0) && (--fine_time <= fine_tune)) {
  366.         fine_time = 0;   /* we are removing pixels to fine tune the clock rate */
  367.      }
  368.      else {  /* demodulate the remaining samples */
  369.         index = ((unsigned short) (in_buf[i] - bias));
  370.         index <<= 8;
  371.         index |= ((unsigned short) (in_buf[i+1] - bias));
  372.  
  373.         out_buf[outptr] = demod[index];
  374.  
  375.         if(++outptr >= BUFLEN) {   /* its time to write the output buffer */
  376.            if(finfile == foutfile) {
  377.           fseek(foutfile, writepos, 0);
  378.           j = fwrite(out_buf, 1, outptr, foutfile);
  379.           writepos = ftell(foutfile);
  380.            }
  381.            else {
  382.           j = fwrite(out_buf, 1, outptr, foutfile);
  383.            }
  384.            if(j != outptr) return 1;   /* !!! file write error */
  385.            outptr = 0;
  386.         }
  387.  
  388.         /* see if we are duplicating pixels */
  389.         if((coarse_tune > 0) && (++coarse_time >= coarse_tune)) {
  390.            coarse_time = 0;   /* adjusting the raw sample rate */
  391.            --i;          /* by duplicating the last pixel */
  392.         }
  393.         else if((fine_tune > 0) && (++fine_time >= fine_tune)) {
  394.            fine_time = 0;      /* fine tuning the clock */
  395.            --i;          /* by duplicating the last pixel */
  396.         }
  397.      }
  398.       }
  399.  
  400.       ++blocks;
  401.       printf("  demodulated %d blocks (%ld bytes) so far.  bias=%d.\r", blocks, readpos, bias);
  402.    }
  403.  
  404.    if(outptr) {   /* write any data remaining in the output buffer */
  405.       if(finfile == foutfile) {   /* overwriting the input file with output data */
  406.      fseek(foutfile, writepos, 0);
  407.      j = fwrite(out_buf, 1, outptr, foutfile);
  408.      writepos = ftell(foutfile);
  409.       }
  410.       else {
  411.      j = fwrite(out_buf, 1, outptr, foutfile);
  412.       }
  413.    }
  414.  
  415.    return 0;
  416. }
  417.  
  418.